﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.SqlServer.Dts.Pipeline.Design;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.DataTransformationServices.DataFlowUI;

using Microsoft.DataTransformationServices.Controls;
using Microsoft.DataWarehouse.Design;
using DP.Sharepoint.SiteWorkflow.SSIS.SiteWorkflowActivationWS;

namespace DP.Sharepoint.SiteWorkflow.SSIS
{

    /// <summary>
    /// user interface for editing mappings of SharePointSiteWorkflowDestination component
    /// </summary>
    public partial class SharePointSiteWorkflowDestinationUI : Form, IDtsComponentUI
    {
        private IDTSComponentMetaData100 _componentMetadata;
        private IServiceProvider _serviceProvider;
        private DataFlowDestinationMappingPage _mappingPage;
        private Exception _currentError;

        DeclarativeSiteWorkflowAssistant _remoteSiteWorkflowAssistant;
        WorkflowParameterMappingManger _mappingManager;
        SiteWorkflowInfo _selectedWorkflow;

        public Dictionary<string, WorkflowParameterMappingManger> _mappingManagerCache = new Dictionary<string, WorkflowParameterMappingManger>();

        public string SiteUrl { get { return _componentMetadata.CustomPropertyCollection[CustomProperties.SiteUrl].Value as string; } set { _componentMetadata.CustomPropertyCollection[CustomProperties.SiteUrl].Value = value; } }
        public string WorkflowName { get { return _componentMetadata.CustomPropertyCollection[CustomProperties.WorkflowName].Value as string; } set { _componentMetadata.CustomPropertyCollection[CustomProperties.WorkflowName].Value = value; } }
        public string WorkflowParameterMapping { get { return _componentMetadata.CustomPropertyCollection[CustomProperties.WorkflowParameterMapping].Value as string; } set { _componentMetadata.CustomPropertyCollection[CustomProperties.WorkflowParameterMapping].Value = value; } }

        #region IDTSUI

        public SharePointSiteWorkflowDestinationUI()
        {
            InitializeComponent();
        }



        public void Delete(IWin32Window parentWindow)
        {

        }

        public bool Edit(IWin32Window parentWindow, Variables variables, Connections connections)
        {

            return this.ShowDialog(parentWindow) == System.Windows.Forms.DialogResult.OK;

        }

        public void Help(IWin32Window parentWindow)
        {

        }

        public void Initialize(IDTSComponentMetaData100 dtsComponentMetadata, IServiceProvider serviceProvider)
        {
            this._componentMetadata = dtsComponentMetadata;
            this._serviceProvider = serviceProvider;


        }

        public void New(IWin32Window parentWindow)
        {

        }


        #endregion

        #region Main Methods

        private bool IsSharepointUrlSpecified
        {
            get
            {
                return !string.IsNullOrEmpty(txtSharepointSiteUrl.Text);
            }
        }

        private void SharePointSiteWorkflowDestinationUI_Load(object sender, EventArgs e)
        {
            this.Text = _componentMetadata.Name;

            txtSharepointSiteUrl.Text = SiteUrl;

            SetupWorkflowParameterManager();

            GetWorkflowMetadataFromSharepoint();

            cmbWorkflowName.Text = WorkflowName;



        }

        private void SetupWorkflowParameterManager()
        {

            try
            {
                if (string.IsNullOrEmpty(WorkflowParameterMapping))
                {
                    _mappingManager = new WorkflowParameterMappingManger();
                }
                else
                    _mappingManager = new WorkflowParameterMappingManger(WorkflowParameterMapping);

                if (!string.IsNullOrEmpty(WorkflowName))
                    _mappingManagerCache[WorkflowName] = _mappingManager;

            }
            catch (Exception exep)
            {
                var ex = new Exception("Error while loading Workflow Parameter Mappings", exep);

                ShowError(ex);

                _mappingManager = new WorkflowParameterMappingManger();

            }


        }

        private void HookupMappingPageEvents()
        {
            pnlMapping.Controls.Clear();

            if (_mappingPage != null)
            {


                _mappingPage.GetExternalColumns -= new GetColumnsEventHandler(mappingPage_GetExternalColumns);
                _mappingPage.GetInternalColumns -= new GetColumnsEventHandler(mappingPage_GetInternalColumns);
                _mappingPage.GetMappedColumns -= new GetMappedColumnsEventHandler(mappingPage_GetMappedColumns);
                _mappingPage.MapColumns -= new MapColumnsEventHandler(mappingPage_MapColumns);
                _mappingPage.UnmapColumns -= new UnmapColumnsEventHandler(mappingPage_UnmapColumns);
                _mappingPage.CanMapColumns -= new CanMapColumnsEventHandler(mappingPage_CanMapColumns);
                _mappingPage.GridColumnTooltipDataNeeded -= new GridColumnTooltipDataNeededEventHandler(mappingPage_GridColumnTooltipDataNeeded);
                _mappingPage.SavePageState -= new SavePageStateEventHandler(mappingPage_SavePageState);

                _mappingPage.Dispose();

            }

            _mappingPage = new DataFlowDestinationMappingPage();

            _mappingPage.InitializePage(pnlMapping);


            _mappingPage.GetExternalColumns += new GetColumnsEventHandler(mappingPage_GetExternalColumns);
            _mappingPage.GetInternalColumns += new GetColumnsEventHandler(mappingPage_GetInternalColumns);
            _mappingPage.GetMappedColumns += new GetMappedColumnsEventHandler(mappingPage_GetMappedColumns);
            _mappingPage.MapColumns += new MapColumnsEventHandler(mappingPage_MapColumns);
            _mappingPage.UnmapColumns += new UnmapColumnsEventHandler(mappingPage_UnmapColumns);
            _mappingPage.CanMapColumns += new CanMapColumnsEventHandler(mappingPage_CanMapColumns);
            _mappingPage.GridColumnTooltipDataNeeded += new GridColumnTooltipDataNeededEventHandler(mappingPage_GridColumnTooltipDataNeeded);
            _mappingPage.SavePageState += new SavePageStateEventHandler(mappingPage_SavePageState);

        }

        private void GetSelectedWorkflowMetadata()
        {
            ClearError();

            try
            {
                if (_remoteSiteWorkflowAssistant != null && (_selectedWorkflow == null || (_selectedWorkflow.WorkflowName != cmbWorkflowName.Text && !string.IsNullOrEmpty(cmbWorkflowName.Text))))
                {
                    _selectedWorkflow = _remoteSiteWorkflowAssistant.GetDeclarativeSiteWorkflowInfo(cmbWorkflowName.Text);

                    if (cmbWorkflowName.Text != null)
                    {
                        if (_mappingManagerCache != null && _mappingManagerCache.ContainsKey(cmbWorkflowName.Text))
                            _mappingManager = _mappingManagerCache[cmbWorkflowName.Text];

                        else
                        {
                            _mappingManager = new WorkflowParameterMappingManger();
                            _mappingManagerCache[cmbWorkflowName.Text] = _mappingManager;


                        }
                    }

                    lblNoInputParameters.Visible = _selectedWorkflow.WorkflowParameters.Count() == 0;

                }


            }
            catch (Exception ex)
            {
                lblNoInputParameters.Visible = false;

                _selectedWorkflow = null;

                SetError(ex);

            }
        }

        private void GetWorkflowMetadataFromSharepoint()
        {
            ClearError();

            try
            {
                if (Uri.IsWellFormedUriString(txtSharepointSiteUrl.Text, UriKind.Absolute))
                {
                    if (_remoteSiteWorkflowAssistant != null)
                    {
                        if (_remoteSiteWorkflowAssistant.SiteUrl.ToString() != txtSharepointSiteUrl.Text)
                        {
                            _remoteSiteWorkflowAssistant.SiteUrl = new Uri(txtSharepointSiteUrl.Text);

                            PupulateWorkflowDropDown();

                        }
                    }
                    else
                    {

                        _remoteSiteWorkflowAssistant = new DeclarativeSiteWorkflowAssistant(new Uri(txtSharepointSiteUrl.Text));

                        PupulateWorkflowDropDown();

                    }

                }
                else
                {
                    SetError(new Exception("Must provide valid Sharepoint Site Url link"));

                }
            }
            catch (Exception e)
            {
                SetError(e);

            }
        }

        private bool PupulateWorkflowDropDown()
        {
            ClearError();

            if (_remoteSiteWorkflowAssistant != null && IsSharepointUrlSpecified)
            {
                try
                {
                    var seltext = cmbWorkflowName.Text;

                    cmbWorkflowName.DataSource = _remoteSiteWorkflowAssistant.GetDeclarativeSiteWorkflowNames().ToArray();

                    if (!string.IsNullOrEmpty(seltext))
                        cmbWorkflowName.Text = seltext;


                    return true;

                }
                catch (Exception e)
                {
                    var err = new Exception("Error while trying to retrieve available site workflows. Please make sure Sharepoint Site Url is correct!", e);

                    ShowError(err);

                    return false;

                }

            }

            return false;

        }

        #endregion

        #region Column Mapper API

        bool mappingPage_SavePageState(object sender, EventArgs args)
        {
            return true;

        }

        void mappingPage_GridColumnTooltipDataNeeded(object sender, GridColumnTooltipDataNeededEventArgs args)
        {
            args.TooltipText = "";


        }


        private static Type GetNormalizedManagedType(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType dt)
        {

            var inputType = SharepointSiteWorkflowDestination.GetManagedType(dt);

            if (inputType == typeof(System.Single) || inputType == typeof(System.Decimal) || inputType == typeof(System.Int16) || inputType == typeof(System.Int32) || inputType == typeof(System.Int64) || inputType == typeof(System.UInt16) || inputType == typeof(System.UInt32) || inputType == typeof(System.UInt64))
                return typeof(System.Double);

            else

                return inputType;

        }

        bool mappingPage_CanMapColumns(object sender, MapColumnsEventArgs args)
        {
            try
            {
                if (args.SourceColumn.Name.StartsWith("<") || args.DestinationColumn.Name.StartsWith("<"))
                    return true;

                IDTSInputColumn100 theCol = ExtractIDTSInputColumn(args);

                if (theCol == null)
                    return false;

                string workflowParameter = ExtractWorkflowParameter(args);

                var paramInfo = _selectedWorkflow.WorkflowParameters.Where(x => x.Name == workflowParameter).FirstOrDefault();

                var inputType = GetNormalizedManagedType(theCol.DataType);

                var paramTypeString = paramInfo.Type.ToLower();

                var inputTypeString = inputType.FullName.ToLower();

                bool res = paramTypeString == inputTypeString;

                if (!res)
                {
                    MessageBox.Show(this, string.Format("Cannot map dataflow column [{2}] of type {0} to workflow parameter [{3}] of type {1}!", inputType, paramInfo.Type, theCol.Name, workflowParameter), _componentMetadata.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);

                }

                return res;

            }
            catch (Exception ex)
            {
                SetError(ex);

                return false;

            }



        }

        void mappingPage_UnmapColumns(object sender, MapColumnsEventArgs args)
        {
            try
            {
                IDTSInputColumn100 theCol = ExtractIDTSInputColumn(args);

                _mappingManager.RemoveMapping(theCol.Name);
            }
            catch (Exception ex)
            {

                SetError(ex);

            }

        }

        private static IDTSInputColumn100 ExtractIDTSInputColumn(MapColumnsEventArgs args)
        {
            IDTSInputColumn100 theCol = null;


            theCol = args.SourceColumn.Tag as IDTSInputColumn100;

            if (theCol == null)
            {
                theCol = args.DestinationColumn.Tag as IDTSInputColumn100;


            }

            return theCol;
        }

        public string ExtractWorkflowParameter(MapColumnsEventArgs args)
        {
            string res = null;


            if (args.SourceColumn.Tag is string)
            {
                res = args.SourceColumn.Tag as string;
            }
            else
            {
                res = args.DestinationColumn.Tag as string;


            }

            return res;

        }

        bool mappingPage_MapColumns(object sender, MapColumnsEventArgs args)
        {
            try
            {

                IDTSInputColumn100 theCol = null;

                string workflowParamName = string.Empty;

                theCol = args.SourceColumn.Tag as IDTSInputColumn100;

                if (theCol == null)
                {
                    theCol = args.DestinationColumn.Tag as IDTSInputColumn100;
                    workflowParamName = args.SourceColumn.Name;

                }
                else
                {
                    workflowParamName = args.DestinationColumn.Name;

                }


                return _mappingManager.AddMapping(theCol.Name, workflowParamName);

            }
            catch (Exception ex)
            {

                SetError(ex);

                return false;

            }

        }

        void mappingPage_GetMappedColumns(object sender, GetMappedColumnsEventArgs args)
        {
            try
            {
                List<DataFlowObject> dfoList = new List<DataFlowObject>();

                IDictionary<string, string> mappingDic = _mappingManager.GetMappingsDictionary();

                foreach (var item in args.SourceColumns)
                {
                    var mapping = mappingDic.Where(x => x.Value == item.Name).FirstOrDefault();

                    if (string.IsNullOrEmpty(mapping.Value))
                    {
                        dfoList.Add(new DataFlowObject());
                    }
                    else
                    {
                        try
                        {
                            var dtsCol = _componentMetadata.InputCollection[0].InputColumnCollection[mapping.Key];

                            dfoList.Add(new DataFlowObject(dtsCol.Name, dtsCol));
                        }
                        catch
                        {
                            _mappingManager.RemoveMapping(mapping.Key);

                            dfoList.Add(new DataFlowObject());
                        }

                    }



                }

                args.MappedColumns = dfoList.ToArray();
            }
            catch (Exception ex)
            {
                SetError(ex);

            }


        }

        void mappingPage_GetInternalColumns(object sender, GetColumnsEventArgs args)
        {
            try
            {
                args.Columns = GetSourceColumns();

            }
            catch (Exception ex)
            {
                SetError(ex);

            }

        }

        private DataFlowObject[] GetSourceColumns()
        {
            List<DataFlowObject> dfoList = new List<DataFlowObject>();

            foreach (IDTSInputColumn100 col in _componentMetadata.InputCollection[0].InputColumnCollection)
            {
                DataFlowObject dfo = new DataFlowObject(col.Name, col);

                dfoList.Add(dfo);

            }

            return dfoList.ToArray();
        }

        void mappingPage_GetExternalColumns(object sender, GetColumnsEventArgs args)
        {


            if (_selectedWorkflow != null)
            {
                List<DataFlowObject> dfoList = new List<DataFlowObject>();

                foreach (var item in _selectedWorkflow.WorkflowParameters)
                {
                    DataFlowObject dfo = new DataFlowObject(item.Name, item.Name);

                    dfoList.Add(dfo);

                }

                args.Columns = dfoList.ToArray();

            }
        }

        #endregion

        #region Error Handling

        private void ClearError()
        {
            txtErrorText.Text = string.Empty;
            pbError.Image = null;
            _currentError = null;

        }

        private void SetError(Exception e)
        {
            pbError.Image = Resources.warning.ToBitmap();

            txtErrorText.Text = e.ToString();
            _currentError = e;

        }

        private void ShowError(Exception err)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(delegate() { ControlUtils.ShowError(err, this); }));

            }
            else

                ControlUtils.ShowError(err, this);

        }
        #endregion

        #region EventHandlers

        private void btnOk_Click(object sender, EventArgs e)
        {



            if (_currentError == null)
            {
                SiteUrl = txtSharepointSiteUrl.Text;
                WorkflowName = cmbWorkflowName.Text;
                WorkflowParameterMapping = _mappingManager.GetMappingsAsString();

                this.DialogResult = System.Windows.Forms.DialogResult.OK;
                this.Close();

            }

        }

        private void txtSharepointSiteUrl_Leave(object sender, EventArgs e)
        {
            GetWorkflowMetadataFromSharepoint();
        }

        private void cmdTestSharepointUrl_Click(object sender, EventArgs e)
        {
            if (this.IsSharepointUrlSpecified)
            {

                if (PupulateWorkflowDropDown())
                {
                    MessageBox.Show(this, "Connection succeeded!", _componentMetadata.Name, MessageBoxButtons.OK, MessageBoxIcon.Information);

                }
            }
            else
            {
                MessageBox.Show(this, "Must provide a valid url!", _componentMetadata.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }



        }

        private void cmbWorkflowName_SelectedValueChanged(object sender, EventArgs e)
        {
            GetSelectedWorkflowMetadata();
        }

        private void tabControlMain_Selecting(object sender, TabControlCancelEventArgs e)
        {

            if (e.TabPageIndex == 1 && _selectedWorkflow == null)
            {

                e.Cancel = true;

                ShowError(new Exception("Must select site workflow before mapping columns!"));

            }
        }

        private void tabControlMain_Selected(object sender, TabControlEventArgs e)
        {
            if (e.TabPageIndex == 1)
            {
                try
                {
                    HookupMappingPageEvents();

                    _mappingPage.ShowPage();
                }
                catch (Exception x)
                {
                    ShowError(x);
                }
            }

        }
        #endregion

        private void btnTestWorkflowStart_Click(object sender, EventArgs e)
        {
            try
            {
                if (_selectedWorkflow != null && _remoteSiteWorkflowAssistant != null)
                {
                    WorkflowTestStartForm frm = new WorkflowTestStartForm();

                    frm.WorkflowInfo = _selectedWorkflow;
                    frm.SiteUrl = _remoteSiteWorkflowAssistant.SiteUrl;
                    frm.Text = "Test Start " + _selectedWorkflow.WorkflowName;

                    frm.ShowDialog(this);

                }
            }
            catch (Exception ex)
            {
                ShowError(ex);

            }

        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process proc = new System.Diagnostics.Process();

            proc.EnableRaisingEvents = false;

            proc.StartInfo.FileName = "http://siteworkflow.codeplex.com/";

            proc.Start();
        }

        private void txtSharepointSiteUrl_TextChanged(object sender, EventArgs e)
        {
            _mappingManagerCache = new Dictionary<string, WorkflowParameterMappingManger>();


        }


    }
}
